package httpResp

import (
	"fmt"
	"gitee.com/igolang/imoney/internal/common/tools"
	"github.com/pkg/errors"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
	"io"
	"net/http"
)

const (
	_           = iota
	ErrCodeFail = 4000 + iota
	ErrCodeHttp
	ErrCodeSystem
	ErrCodeNotFound
	ErrCodeDuplicated
	ErrCodeInvalidParams
	ErrCodeInvalidVerifyCode
	ErrCodeInvalidJson
	ErrCodeBlackFlg
	ErrCodeNoVendor
	ErrCodeSign
	ErrInput
	ErrCodeInvalidParamsType
	ErrCodeEmptyData
	ErrCodeEmptySlice
	ErrCodeEmptyObject
	ErrCodeUserNotExists
	ErrCodeInvalidPassword
	ErrCodeInvalidUser
	ErrCodeRoleNotExists
)

const (
	ErrCodeMsgWarning   = 601
	ErrCodeNoPermission = http.StatusForbidden
	ErrCodeInvalidToken = http.StatusUnauthorized
)

var errCodeToMsg = map[int]string{
	ErrCodeFail:              "失败",
	ErrCodeHttp:              "请求错误",
	ErrCodeSystem:            "系统错误",
	ErrCodeNotFound:          "资源未找到",
	ErrCodeDuplicated:        "资源重复",
	ErrCodeNoPermission:      "没有权限",
	ErrCodeInvalidParams:     "参数错误",
	ErrCodeInvalidVerifyCode: "验证码错误",
	ErrCodeInvalidJson:       "json解析错误",
	ErrCodeBlackFlg:          "在黑名单中",
	ErrCodeNoVendor:          "没有这个短信服务商",
	ErrCodeSign:              "验签错误",
	ErrInput:                 "输入错误",
	ErrCodeInvalidParamsType: "错误的参数类型",
	ErrCodeEmptyData:         "空数据",
	ErrCodeEmptySlice:        "空数组",
	ErrCodeEmptyObject:       "空对象",
	ErrCodeUserNotExists:     "用户不存在",
	ErrCodeInvalidPassword:   "用户名或密码错误",
	ErrCodeInvalidUser:       "用户账号已停用",
	ErrCodeRoleNotExists:     "角色不存在",
	ErrCodeInvalidToken:      "认证失败",
}

func getMsg(code int) string {
	msg := errCodeToMsg[code]
	if msg == "" {
		msg = http.StatusText(code)
	}
	if msg == "" {
		msg = errCodeToMsg[ErrCodeFail]
	}
	return msg
}

type codeErr struct {
	code int
	msg  string
}

func (r codeErr) Error() string {
	return fmt.Sprintf("code: %d, msg: %s", r.code, r.msg)
}

func ErrorCode(code int, msg ...string) error {
	var message string
	if len(msg) > 0 {
		message = msg[0]
	}
	if message == "" {
		message = getMsg(code)
	}
	return codeErr{
		code: code,
		msg:  message,
	}
}

func ErrWarning(format string, args ...any) error {
	return codeErr{
		code: ErrCodeMsgWarning,
		msg:  fmt.Sprintf(format, args...),
	}
}

func ErrPanic(format string, args ...any) error {
	return codeErr{
		code: ErrCodeSystem,
		msg:  fmt.Sprintf(format, args...),
	}
}

func IsErrorCode(err any) bool {
	_, ok := err.(codeErr)
	return ok
}

func AsErrorCode(code int, err any) bool {
	e, ok := err.(codeErr)
	if !ok {
		return false
	}
	return e.code == code
}

func IsNotFoundErr(err error) bool {
	return errors.Is(err, gorm.ErrRecordNotFound) || errors.Is(err, redis.Nil) || errors.Is(err, io.EOF)
}

func ErrorResponse(err any, resp *Resp) {
	var (
		msg  string
		code = ErrCodeFail
	)
	switch e := err.(type) {
	case int:
		code = e
	case codeErr:
		code = e.code
		msg = e.msg
	case error:
		if tools.EnvProd() && IsNotFoundErr(e) {
			code = ErrCodeNotFound
		} else {
			msg = e.Error()
		}
	case string:
		msg = e
	default:
		msg = fmt.Sprintf("%v", err)
	}

	if msg == "" {
		msg = getMsg(code)
	}

	if tools.EnvProd() && code == ErrCodeSystem {
		msg = getMsg(code)
	}

	resp.Code = code
	resp.Message = msg
}
